package cn.lg.soar.mvc.util;

import cn.lg.soar.common.constant.MDCKey;
import cn.lg.soar.common.model.LogDTO;
import cn.lg.soar.common.util.ExceptionUtil;
import cn.lg.soar.common.util.IpUtil;
import cn.lg.soar.common.util.current.ICurrentUser;
import cn.lg.soar.common.util.current.ThreadContext;
import cn.lg.soar.common.util.current.UserContext;
import cn.lg.soar.core.handler.log.ILogCollector;
import cn.lg.soar.core.util.InnerSerializeUtils;
import cn.lg.soar.core.util.SoarSubscriber;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.MDC;

import java.time.LocalDateTime;

/**
 * 日志工具，与ILogHandler功能一致，仅为方便使用提供
 * @author luguoxiang
 * @date 2022/4/23
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class LogUtils {

    private static ILogCollector collector;

    static {
        SoarSubscriber.subscribeRunner(a -> {
            collector = a.getBean(ILogCollector.class);
        });
    }

    /**
     * 记录日志
     * @param log 日志
     */
    public static void log(LogDTO log) {
        collector.add(log);
    }

    /**
     * 记录日志
     * @param title 操作
     * @param args 参数
     */
    public static void log(String title, Object args) {
        LogDTO log = new LogDTO();
        log.setTitle(title);
        log.setStartTime(LocalDateTime.now());
        log.setArgs(InnerSerializeUtils.toJson(args));
        fillUserInfo(log);
        fillRequestInfo(log);
        collector.add(log);
    }

    /**
     * 记录日志
     * @param title 操作
     * @param args 参数
     * @param startTime 开始时间
     */
    public static void log(String title, Object args, LocalDateTime startTime) {
        LogDTO log = new LogDTO();
        log.setTitle(title);
        log.setStartTimeAndDuration(startTime);
        log.setArgs(InnerSerializeUtils.toJson(args));
        fillUserInfo(log);
        fillRequestInfo(log);
        collector.add(log);
    }

    /**
     * 记录日志
     * @param title 操作
     * @param args 参数
     * @param result 结果
     */
    public static void log(String title, Object args, Object result) {
        LogDTO log = new LogDTO();
        log.setTitle(title);
        log.setStartTime(LocalDateTime.now());
        log.setArgs(InnerSerializeUtils.toJson(args));
        log.setResult(InnerSerializeUtils.toJson(result));
        fillUserInfo(log);
        fillRequestInfo(log);
        collector.add(log);
    }

    /**
     * 记录日志
     * @param title 操作
     * @param args 参数
     * @param result 结果
     * @param startTime 开始时间
     */
    public static void log(String title, Object args, Object result, LocalDateTime startTime) {
        LogDTO log = new LogDTO();
        log.setTitle(title);
        log.setStartTimeAndDuration(startTime);
        log.setArgs(InnerSerializeUtils.toJson(args));
        log.setResult(InnerSerializeUtils.toJson(result));
        fillUserInfo(log);
        fillRequestInfo(log);
        collector.add(log);
    }

    /**
     * 记录日志
     * @param title 操作
     * @param args 参数
     * @param ex 异常
     */
    public static void log(String title, Object args, Throwable ex) {
        LogDTO log = new LogDTO();
        log.setTitle(title);
        log.setStartTime(LocalDateTime.now());
        log.setArgs(InnerSerializeUtils.toJson(args));
        log.setErrorStack(ExceptionUtil.getRefinedStackTrace(ex, 20));
        fillUserInfo(log);
        fillRequestInfo(log);
        collector.add(log);
    }

    /**
     * 记录日志
     * @param title 操作
     * @param args 参数
     * @param ex 异常
     * @param startTime 开始时间
     */
    public static void log(String title, Object args, Throwable ex, LocalDateTime startTime) {
        LogDTO log = new LogDTO();
        log.setTitle(title);
        log.setStartTimeAndDuration(startTime);
        log.setArgs(InnerSerializeUtils.toJson(args));
        log.setErrorStack(ExceptionUtil.getRefinedStackTrace(ex, 20));
        fillUserInfo(log);
        fillRequestInfo(log);
        collector.add(log);
    }


    /**
     * 记录日志
     * @param title 标题
     */
    public static void logText(String title) {
        LogDTO log = new LogDTO();
        log.setTitle(title);
        log.setStartTime(LocalDateTime.now());
        log.setDuration(0);
        fillUserInfo(log);
        fillRequestInfo(log);
        collector.add(log);
    }

    /**
     * 记录日志
     * @param title 标题
     * @param content 内容
     */
    public static void logText(String title, String content) {
        LogDTO log = new LogDTO();
        log.setTitle(title);
        log.setContent(content);
        log.setStartTime(LocalDateTime.now());
        log.setDuration(0);
        fillUserInfo(log);
        fillRequestInfo(log);
        collector.add(log);
    }

    /**
     * 记录日志
     * @param title 标题
     * @param content 内容
     * @param startTime 开始时间
     */
    public static void logText(String title, String content, LocalDateTime startTime) {
        LogDTO log = new LogDTO();
        log.setTitle(title);
        log.setContent(content);
        log.setStartTimeAndDuration(startTime);
        fillUserInfo(log);
        fillRequestInfo(log);
        collector.add(log);
    }

    /**
     * 填充用户信息
     * @param log
     */
    public static void fillUserInfo(LogDTO log) {
        log.setTenantId(ThreadContext.getTenantId());
        // 用户相关
        ICurrentUser user = UserContext.getUserNullable();
        if (user == null) {
            log.setUserId(0L);
            log.setUserType(0);
            log.setClientType(0);
        } else {
            log.setUserId(user.getId());
            log.setUserType(user.getUserType());
            log.setClientType(user.getClientType());
        }
    }

    /**
     * 填充请求信息
     * @param log
     */
    public static void fillRequestInfo(LogDTO log) {
        log.setTraceId(MDC.get(MDCKey.TRACE_ID));
        log.setPath(ThreadContext.getResource());
        // 请求相关
        if (ServletUtils.isServletContext()) {
            HttpServletRequest request = ServletUtils.getRequest();
            log.setClientIp(IpUtil.getRemoteIp(request));
            log.setUserAgent(request.getHeader("user-agent"));
        } else {
            log.setClientIp("");
            log.setUserAgent("");
        }
    }

}
